package com.boarsoft.boar.deploy.app.action;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.boarsoft.agent.AgentService;
import com.boarsoft.bean.LogonI;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.BaseConfig;
import com.boarsoft.boar.app.AppInstBiz;
import com.boarsoft.boar.app.action.AppBaseAction;
import com.boarsoft.boar.common.Constants;
import com.boarsoft.boar.context.ActionContext;
import com.boarsoft.boar.deploy.app.AppDeployBiz;
import com.boarsoft.boar.deploy.entity.AppDeployInfo;
import com.boarsoft.boar.deploy.plan.bean.BuildRequest;
import com.boarsoft.boar.entity.AppInfo;
import com.boarsoft.boar.entity.AppInst;
import com.boarsoft.boar.proj.ProjBiz;
import com.boarsoft.cache.Cache;
import com.boarsoft.common.Authorized;
import com.boarsoft.common.Util;
import com.boarsoft.common.dao.PagedResult;
import com.boarsoft.common.util.RandomUtil;
import com.boarsoft.flow.core.SimpleFlowEngine;
import com.boarsoft.rpc.core.RpcContext;
import com.boarsoft.web.login.Logined;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@RestController
@RequestMapping("/app")
public class AppDeployAction extends AppBaseAction {
	private static final Logger log = LoggerFactory.getLogger(AppDeployAction.class);

	@Autowired
	protected AppDeployBiz appDeployBiz;
	@Autowired
	protected AppInstBiz appInstBiz;
	@Autowired
	protected ProjBiz projBiz;

	@Autowired
	@Lazy(value = true)
	@Qualifier("agentX")
	protected AgentService agentX;
	@Autowired
	protected SimpleFlowEngine flowEngine;

	/**
	 * 保存AppDeployInfo时，需从parentId开始，向上找到ProjInfo
	 * 
	 * @param parentId
	 * @param o
	 * @return
	 */
	@RequestMapping("/save.do")
	@Authorized(code = "app.save")
	public ReplyInfo<Object> save(String parentId, AppDeployInfo o) {
		if (Util.strIsEmpty(o.getId())) {
			if (Util.strIsEmpty(parentId)) {
				return Constants.REPLY_WARN_INVALID;
			}
			return this.add(parentId, o);
		}
		o.setProjId(parentId);
		return this.update(o);
	}

	/**
	 * 
	 * @param instId
	 * @param appId
	 * @param env
	 * @param wssid
	 *            websocket sessionId
	 * @return
	 */
	@RequestMapping("/deploy.do")
	@Authorized(code = "app.deploy")
	public ReplyInfo<Object> deploy(@Logined LogonI<String> logon, String instId, String appId, String env, String wssid) {
		// TODO 检查参数：appId, instId, env
		// 部署指定的应用实例（一个）
		List<AppInst> instLt = null;
		if (Util.strIsEmpty(instId)) {
			PagedResult<AppInst> pr = appInstBiz.list(//
					env, null, appId, null, null, null, null, null, 1, Integer.MAX_VALUE);
			instLt = pr.getList();
		} else {
			instLt = new ArrayList<AppInst>();
			String[] ka = instId.split(",");
			for (String k : ka) {
				AppInst inst = appInstBiz.get(k);
				if (inst == null) {
					continue;
				}
				instLt.add(inst);
			}
		}
		if (instLt == null || instLt.isEmpty()) {
			return new ReplyInfo<Object>(false, Constants.ERROR_NOTFOUND);
		}
		// get方法取出的是一个脱管对象
		AppDeployInfo app = (AppDeployInfo) appBiz.get(appId);
		app.setInsts(null);
		app.setLibs(null);
		app.setFiles(null);
		//
		for (AppInst inst : instLt) {
			appInstBiz.status(inst.getId(), AppInst.STATUS_DEPLOYING);
		}
		// 保存sessionId和本次部署的id的关系
		String id = RandomUtil.randomUUID();
		// List<BuildPlanItem> items = planItemBiz.list2(id);
		BuildRequest p = new BuildRequest();
		p.setEnv(env);
		p.setId(RandomUtil.randomUUID());
		// p.setItems(items);
		p.setPlanId(id);
		// p.setToken(token);
		// p.setWssid(wssid);
		//
		String flowId = app.getDeployCode();
		if (Util.strIsEmpty(flowId)) {
			return new ReplyInfo<Object>(false, Constants.ERROR_NOTFOUND);
		}
		try {
			// 使用 websocket session id + 时间 作为流程ID
			Cache cache = ActionContext.getCache();
			cache.put("deploy", id, p);
			// 异步去执行
			flowEngine.submit(flowId, id, p, null);
			return new ReplyInfo<Object>(true, id);
		} catch (Throwable e) {
			log.error("Error on deploy app instances of app {}", app, e);
			return new ReplyInfo<Object>(false, Constants.ERROR_INTERNAL);
		}
	}

	@RequestMapping("/undeploy.do")
	@Authorized(code = "app.inst.undeploy")
	public ReplyInfo<Object> undeploy(String id) {
		// 更新状态
		AppInst inst = appInstBiz.get(id);
		AppDeployInfo app = (AppDeployInfo) appBiz.get(inst.getAppId());
		String addr = new StringBuilder().append(inst.getIp()).append(":")//
				.append(BaseConfig.AGENTX_PORT).toString();
		String cmd = String.format("%s/%s", inst.getDeployPath(), app.getUndeployCode());
		log.info("Ask {} undeploy app instance {} with: {}", addr, inst, cmd);
		// 取inst的path而不是app的deployPath
		RpcContext.specify2(addr);
		try {
			// 执行应用实例目录下的启动脚本
			// TODO agentX.executeShell(cmd);
			agentX.delete(inst.getDeployPath());
			appInstBiz.status(id, AppInst.STATUS_MISSING);
			log.info("App instance {} is removed successfully", inst);
			return ReplyInfo.SUCCESS;
		} catch (Exception e) {
			log.error("Error on remove app instance {}", inst, e);
			return new ReplyInfo<Object>(Constants.ERROR_INTERNAL);
		} finally {
			RpcContext.specify2(null);
		}
	}

	@JsonIgnoreProperties({ "svcs", "libs", "insts", "apps", "files", "protocols" })
	@RequestMapping("/list.do")
	@Authorized(code = "app.list")
	public ReplyInfo<Object> list(String id, String projId, String key, String orderBy, int pageNo, int pageSize) {
		PagedResult<AppInfo> pr = appBiz.list(id, projId, key, orderBy, pageNo, pageSize);
		return new ReplyInfo<Object>(true, pr);
	}
}